use ctp_rs::{MdApi, MdSpiMsg, ReqUserLoginField};
use std::sync::{Arc, mpsc::channel};
use dotenv::dotenv;
use std::env;
use tokio::sync::mpsc;
use std::thread;

// for more fronts, see: http://www.openctp.cn/simenv.html

#[tokio::main]
async fn main() {
    dotenv().ok();
    // 从 .env/环境变量读取
    let front_md = env::var("FRONT_MD").unwrap();
    let flow_path = env::var("FLOW_PATH").unwrap();
    let instruments_env = env::var("INSTRUMENTS").unwrap();
    let broker_id = env::var("BROKER_ID").unwrap();
    let user_id = env::var("USER_ID").unwrap();
    let password = env::var("PASSWORD").unwrap();

    // CTP SPI 仍使用 std::sync::mpsc::Sender
    let (std_tx, std_rx) = channel::<MdSpiMsg>();
    let api = Arc::new(MdApi::CreateMdApiAndSpi(
        std_tx,
        flow_path.clone(),
        false,
        false,
        true,
    ));
    api.RegisterFront(front_md);
    api.Init();

    // 使用 tokio mpsc 接收，创建一个桥接线程把 std_rx -> tokio_tx
    let (tokio_tx, mut tokio_rx) = mpsc::unbounded_channel::<MdSpiMsg>();
    thread::spawn(move || {
        while let Ok(msg) = std_rx.recv() {
            // 如果接收端已关闭，结束桥接线程
            if tokio_tx.send(msg).is_err() {
                break;
            }
        }
    });

    while let Some(msg) = tokio_rx.recv().await {
        match msg {
            MdSpiMsg::OnFrontConnected => {
                println!("front connected");
                let mut req = ReqUserLoginField::default();
                req.BrokerID = broker_id.clone();
                req.UserID = user_id.clone();
                req.Password = password.clone();
                api.ReqUserLogin(req, 0);
            }
            MdSpiMsg::OnRspUserLogin(_, rsp_info, _, _) => {
                if rsp_info.ErrorID != 0 {
                    println!("user login failed: {:?}", rsp_info);
                    continue;
                } else {
                    println!("user login success: {:?}", rsp_info);
                    let instruments: Vec<String> = instruments_env
                        .split(',')
                        .map(|s| s.trim().to_string())
                        .filter(|s| !s.is_empty())
                        .collect();
                    let len = instruments.len() as i32;
                    println!("Subscribing to instruments: {:?}", instruments);
                    api.SubscribeMarketData(instruments, len);
                }
            }
            MdSpiMsg::OnRtnDepthMarketData(tick) => {
                println!("{:?}", tick);
            }
            _ => {}
        }
    }
}
